#include "f1c100s_malloc.h"
#include "sys_uart.h"

__align(1024) u8 membase[MAX_MEM_SIZE]; // 内存池

// 内存管理控制器
__align(4) struct _m_mallco_dev mallco_dev =
	{
		mem_init,	 // 内存初始化
		mem_perused, // 内存使用率
		0,			 // 内存管理状态表
		0,			 // 内存管理未就绪
};
// 复制内存
//*des:目的地址
//*src:源地址
// n:需要复制的内存长度(字节为单位)
void mymemcpy(void *des, void *src, u32 n)
{
	u8 *xdes = des;
	u8 *xsrc = src;
	while (n--)
	{
		*xdes++ = *xsrc++;
	}
}
// 设置内存
//*s:内存首地址
// c :要设置的值
// count:需要设置的内存大小(字节为单位)
void mymemset(void *s, u8 c, u32 count)
{
	u8 *xs = s;
	while (count--)
	{
		*xs++ = c;
	}
}
// 内存管理初始化
void mem_init(void)
{
	mymemset(membase, 0, sizeof(membase)); // 内存池素有数据清零
	mallco_dev.memrdy = 1;				   // 内存管理初始化OK
}
// 获取内存使用率
// 返回值:使用率(0~100)
u8 mem_perused(void)
{
	u32 used = 0;
	u32 i;
	for (i = 0; i < MEM_ALLOC_TABLE_SIZE; i++)
	{
		if (mallco_dev.memmap[i])
			used++;
	}
	return (u8)((float)used / (float)MEM_ALLOC_TABLE_SIZE * 100.0);
}
// 内存分配(内部调用)
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
u32 mem_malloc(u32 size)
{
	signed long offset = 0;
	u32 nmemb;	   // 需要的内存块数
	u32 cmemb = 0; // 连续空内存块数
	u32 i;
	if (!mallco_dev.memrdy)
		mallco_dev.init(); // 未初始化,先执行初始化
	if (size == 0)
		return 0XFFFFFFFF;		   // 不需要分配
	nmemb = size / MEM_BLOCK_SIZE; // 获取需要分配的连续内存块数
	if (size % MEM_BLOCK_SIZE)
		nmemb++;
	for (offset = MEM_ALLOC_TABLE_SIZE - 1; offset >= 0; offset--) // 搜索整个内存控制区
	{
		if (!mallco_dev.memmap[offset])
			cmemb++; // 连续空内存块数增加
		else
			cmemb = 0;		// 连续内存块清零
		if (cmemb == nmemb) // 找到了连续nmemb个空内存块
		{
			for (i = 0; i < nmemb; i++) // 标注内存块非空
			{
				mallco_dev.memmap[offset + i] = nmemb;
			}
			return (offset * MEM_BLOCK_SIZE); // 返回偏移地址
		}
	}
	return 0XFFFFFFFF; // 未找到符合分配条件的内存块
}
// 释放内存(内部调用)
// offset:内存地址偏移
// 返回值:0,释放成功;1,释放失败;
u8 mem_free(u32 offset)
{
	int i;
	if (!mallco_dev.memrdy) // 未初始化,先执行初始化
	{
		mallco_dev.init();
		return 1; // 未初始化
	}
	if (offset < MAX_MEM_SIZE) // 偏移在内存池内.
	{
		int index = offset / MEM_BLOCK_SIZE;  // 偏移所在内存块号码
		int nmemb = mallco_dev.memmap[index]; // 内存块数量
		for (i = 0; i < nmemb; i++)			  // 内存块清零
		{
			mallco_dev.memmap[index + i] = 0;
		}
		return 0;
	}
	else
		return 2; // 偏移超区了.
}
// 释放内存(外部调用)
// ptr:内存首地址
void f1c100s_free(void *ptr)
{
	u32 offset;
	if (ptr == NULL)
		return; // 地址为0.
	offset = (u32)ptr - (u32)&membase;
	mem_free(offset); // 释放内存
}
// 分配内存(外部调用)
// size:内存大小(字节)
// 返回值:分配到的内存首地址.
void *f1c100s_malloc(u32 size)
{
	u32 offset;
	offset = mem_malloc(size);
	if (offset == 0XFFFFFFFF)
		return NULL;
	else
		return (void *)((u32)&membase + offset);
}

// 分配对齐内存-最大1024
//  blk_size:块对齐大小(字节)
//  blk_n:块数量
// 返回值:分配到的内存首地址.
void *f1c100s_malloc_Align(u32 blk_n, u32 blk_size)
{
	void *addr1 = 0;
	void *addr2 = 0;
	//	int Fx=blk_size/MEM_BLOCK_SIZE;
	u32 i;
	// sysprintf("blk_n=%d  blk_size=%d\n\r",blk_n,blk_size);
	if (blk_size > 1024)
	{
		sysprintf("ERR: mymalloc_Align() blk_size>1024 \n\r");
		return NULL;
	}
	if ((blk_size % MEM_BLOCK_SIZE) != 0)
	{
		sysprintf("ERR: mymalloc_Align() blk_size Align err! \n\r");
		return NULL;
	}
	for (i = 0; i < (MEM_ALLOC_TABLE_SIZE); i++)
	{
		addr2 = f1c100s_malloc(blk_n * blk_size);
		if (addr2 == NULL)
		{
			if (addr1)
				f1c100s_free(addr1);
			return NULL;
		}
		if (((u32)addr2 % blk_size) == 0)
		{
			if (addr1)
				f1c100s_free(addr1);
			return addr2;
		}
		// free全部
		if (addr1)
			f1c100s_free(addr1);
		if (addr2)
			f1c100s_free(addr2);
		// malloc  ddr1
		addr1 = f1c100s_malloc(MEM_BLOCK_SIZE * (i + 1));
		if (addr1 == NULL)
			return NULL;
	}
	// free全部
	if (addr1)
		f1c100s_free(addr1);
	if (addr2)
		f1c100s_free(addr2);
	sysprintf("ERR: mymalloc_Align() err! \n\r");
	return NULL;
}

// 重新分配内存(外部调用)
//*ptr:旧内存首地址
// size:要分配的内存大小(字节)
// 返回值:新分配到的内存首地址.
void *myrealloc(void *ptr, u32 size)
{
	u32 offset;
	offset = mem_malloc(size);
	if (offset == 0XFFFFFFFF)
		return NULL;
	else
	{
		mymemcpy((void *)((u32)&membase + offset), ptr, size); // 拷贝旧内存内容到新内存
		f1c100s_free(ptr);									   // 释放旧内存
		return (void *)((u32)&membase + offset);			   // 返回新内存首地址
	}
}

// 分配测试
int mymalloc_test(void)
{
	u8 *ptr[10];
	u32 i;

	for (i = 0; i < 5; i++)
	{
		ptr[i] = (u8 *)f1c100s_malloc_Align(32, 1024);
		sysprintf("ADDR%d:%x \n\r", i, ptr[i]);
		sysprintf("查使用率:%d\n\r", mallco_dev.perused());
	}
	for (i = 0; i < 5; i++)
	{
		f1c100s_free(ptr[i]);
	}

	for (i = 0; i < 5; i++)
	{
		ptr[i] = (u8 *)f1c100s_malloc_Align(1, 1024);
		sysprintf("ADDR%d:%x \n\r", i, ptr[i]);
		sysprintf("查使用率:%d\n\r", mallco_dev.perused());
	}
	for (i = 0; i < 5; i++)
	{
		f1c100s_free(ptr[i]);
	}
	//	//------------------------------------------------------
	//	for(i=0;i<15;i++)
	//	{
	//		ptr[i]=(u8*)mymalloc(1024);sysprintf("ADDR%d:%x \n\r",i,ptr[i]);
	//		sysprintf("查使用率:%d\n\r",mallco_dev.perused());
	//	}
	//	for(i=0;i<5;i++)
	//	{
	//		myfree(ptr[i]);
	//	}
	//	for(i=0;i<5;i++)
	//	{
	//		ptr[i]=(u8*)mymalloc(1024);sysprintf("ADDR%d:%x \n\r",i,ptr[i]);
	//		sysprintf("查使用率:%d\n\r",mallco_dev.perused());
	//	}

	while (1)
	{
	}
}
